package com.arsenavid.aterrizacomopuedas.service;

import java.math.BigDecimal;
import java.security.Provider.Service;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.transaction.Transaction;

import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import com.arsenavid.aterrizacomopuedas.model.Aeropuerto;
import com.arsenavid.aterrizacomopuedas.model.Billete;
import com.arsenavid.aterrizacomopuedas.model.Vuelo;

public class GestionVuelosServiceImpl implements GestionVuelosService {

	public static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("data");

	public GestionVuelosServiceImpl() {
	}
	
	private Date calcularSiguienteDia(Date dia) {
		Calendar calendario = Calendar.getInstance();
		
		calendario.setTime(dia);
		calendario.add(Calendar.DATE, 40);
		calendario.set(Calendar.HOUR, 0);
		calendario.set(Calendar.MINUTE, 0);
		calendario.set(Calendar.SECOND, 0);
		calendario.set(Calendar.MILLISECOND, 0);
		Date a = new Date();
		a = calendario.getTime();
		return calendario.getTime();
	}
	
	private Date sumaMinutos(Date dia, int minutos) {
		Calendar calendario = Calendar.getInstance();
		
		calendario.setTime(dia);
		calendario.add(Calendar.DATE, 0);
		calendario.set(Calendar.HOUR, 0);
		calendario.set(Calendar.MINUTE, minutos);
		calendario.set(Calendar.SECOND, 0);
		calendario.set(Calendar.MILLISECOND, 0);
		return calendario.getTime();
	}
	
	public Set<Vuelo> obtenerVuelos(String nombreAeropuertoOrigen, 
									String nombreAeropuertoDestino, Date dia) {
		
		EntityManager em = null;
		
		try {
			em = factory.createEntityManager();

			List<Vuelo> vuelos =
					em.createNamedQuery("vuelosPorNombreOrigenNombreDestinoDia")
					.setParameter("origen", nombreAeropuertoOrigen)
					.setParameter("destino", nombreAeropuertoDestino)
					.setParameter("dia", dia)
					.setParameter("diaPosterior", calcularSiguienteDia(dia))
					.getResultList();
			
			Set<Vuelo> vuelosSet = new HashSet<Vuelo>();
			vuelosSet.addAll(vuelos);
			return vuelosSet;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}
	
	public List<Vuelo> obtenerVuelos(String aeropuertoOrigen,String aeropuertoDestino, 
			Date fechaPartida, int firstResult, int maxResusutls, int orden) {

		EntityManager em = null;
		
		try {
			em = factory.createEntityManager();
			
			EntityTransaction tx = em.getTransaction();
			tx.begin();
			
			org.hibernate.Session session = 
					(org.hibernate.Session) em.getDelegate();
			
			Aeropuerto origen = em.getReference(Aeropuerto.class, aeropuertoOrigen);
			Aeropuerto destino = em.getReference(Aeropuerto.class, aeropuertoDestino);
			
			//Crear swicth para el criterio de ordenación
			Order criterioOrdenacion;
			switch (orden) {
				
				case 2:
					criterioOrdenacion = Order.desc("horaSalida");
					break;
				case 3:
					criterioOrdenacion = Order.asc("precio");
					break;
				case 4:
					criterioOrdenacion = Order.desc("precio");
					break;
	
				default:
					//Hora de salida asc por defecto
					criterioOrdenacion = Order.asc("horaSalida");
					break;
			}
					
			List<Vuelo> vuelos =
					session.createCriteria(Vuelo.class)
					.add(Restrictions.eq("aeropuertoOrigen", origen))
					.add(Restrictions.eq("aeropuertoDestino", destino))
					.add(Restrictions.ge("horaSalida", fechaPartida))
					.addOrder(criterioOrdenacion)
					.setFirstResult(firstResult)
					.setMaxResults(maxResusutls)
					.list();
			
			tx.commit();
			
			return vuelos;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}
	
	
	public void crearVuelosFalsos(Date fechaInicial, Date fechaFinal) {
		
		String [] iatas = {"BCN","MAD","VAL","ZAR","SEV"};
		EntityManager em = null;
		
		try {
			em = factory.createEntityManager();
			EntityTransaction tx = em.getTransaction();
			tx.begin();
			
			for (int i = 0; i < 2000; i++) {
				
				String iata1 = iatas[(int)(Math.random() * iatas.length)];
				Aeropuerto refAeropuerto1 = em.getReference(Aeropuerto.class, iata1);
				String iata2 = iatas[(int)(Math.random() * iatas.length)];
				Aeropuerto refAeropuerto2 = em.getReference(Aeropuerto.class, iata2);
				
				Vuelo v = new Vuelo();
				v.setAeropuertoOrigen(refAeropuerto1);
				v.setAeropuertoDestino(refAeropuerto2);
				v.setHoraSalida(sumaMinutos(fechaInicial, 10*i));
				v.setHoraLlegada(sumaMinutos(fechaFinal, 20*i));
				v.setPlazas(100);
				v.setPlazasLibres(50);
				v.setPrecio(new BigDecimal((10 + (Math.random()*1000))));
				em.persist(v);
			}
			tx.commit();
		} finally {
			if (em != null) {
				em.close();
			}
		}		
	}
	
	
	public Set<Aeropuerto> obtenerAeropuertos() {
		
		String jpql = "select a"
					+" from Aeropuerto as a";
		
		EntityManager em = null;
		try {
			em = factory.createEntityManager();
			
			List<Aeropuerto> aeropuertos = em.createQuery(jpql).getResultList();
			
			Set<Aeropuerto> aeropuertoSet = new HashSet<Aeropuerto>();
			aeropuertoSet.addAll(aeropuertos);
			return aeropuertoSet;
			
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public Vuelo obtenerVueloById(int vueloseleccionado) {
		
		EntityManager em = null;
		Vuelo vuelo = new Vuelo();
		try {
			em = factory.createEntityManager();
			vuelo = (Vuelo) em.find(Vuelo.class, vueloseleccionado);
		} finally {
			if (em != null) {
				em.close();
			}
		}
		return vuelo;
	}


	public void comprarBillete(String nombre, String cifnif,
			int vueloseleccionado) {
		
		EntityManager em = null;
		try {
			em = factory.createEntityManager();
			EntityTransaction tx = em.getTransaction();
			tx.begin();
			
			Billete billete = new Billete();
			Vuelo vuelo = em.find(Vuelo.class, vueloseleccionado);
			billete.setIdvuelo(vuelo);
			billete.setNifcif(cifnif);
			billete.setNombre(nombre);
			em.persist(billete);
			
			tx.commit();	
		} finally {
			if (em != null) {
				em.close();
			}
		}
		
		
	}
	
}
